package com.gs.wechatdemo.activity;

import android.Manifest;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.google.gson.reflect.TypeToken;
import com.gs.wechatdemo.MyApplication;
import com.gs.wechatdemo.R;
import com.gs.wechatdemo.adapter.ChatContentAdapter;
import com.gs.wechatdemo.audio.AudioPresenter;
import com.gs.wechatdemo.audio.IAudioView;
import com.gs.wechatdemo.audio.RecordAudioTextView;
import com.gs.wechatdemo.audio.RecordVoicePopWindow;
import com.gs.wechatdemo.constant.AllConstants;
import com.gs.wechatdemo.constant.ChatCode;
import com.gs.wechatdemo.constant.ImageEditCode;
import com.gs.wechatdemo.control.OnRecyclerViewScrollListener;
import com.gs.wechatdemo.db.bean.ChatBean;
import com.gs.wechatdemo.db.bean.ContactBean;
import com.gs.wechatdemo.db.dto.EventBean;
import com.gs.wechatdemo.db.dto.MsgContentDto;
import com.gs.wechatdemo.db.dto.MsgDto;
import com.gs.wechatdemo.db.dto.UserDto;
import com.gs.wechatdemo.db.sqlite.SQLiteUtil;
import com.gs.wechatdemo.dialog.CommDialogUtils;
import com.gs.wechatdemo.signalr.SignalRCode;
import com.gs.wechatdemo.signalr.SignalRUtil;
import com.gs.wechatdemo.util.DateUtil;
import com.gs.wechatdemo.util.DensityUtil;
import com.gs.wechatdemo.util.FileUtils;
import com.gs.wechatdemo.util.GsonUtil;
import com.gs.wechatdemo.util.ImageUtil;
import com.gs.wechatdemo.util.PermissionUtil;
import com.gs.wechatdemo.util.PhotoUtil;
import com.gs.wechatdemo.util.SPUtil;
import com.gs.wechatdemo.util.WindowUtil;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ChatListActivity extends BaseListActivity<ChatBean> implements View.OnClickListener, IAudioView.View {

    private ChatContentAdapter adapter;
    private ImageView ivLeft, ivAdd, ivPlay;
    private TextView tvSend, tvName, tvStatus;
    private EditText etInput;
    private boolean isPlay;
    private int mLastPosition, mViewType, mLevel;
    private IAudioView.Presenter audioPresenter;
    private RecordVoicePopWindow mRecordVoicePopWindow;
    private RecordAudioTextView tvAudio;
    private AnimationDrawable mAnim;
    private String myId, myPhoto, otherId;
    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == ImageEditCode.EDIT_MSG) {
                if (msg.arg1 == ImageEditCode.BITMAP_ARG) {
                    Bitmap bitmap = (Bitmap) msg.obj;
                    String base64 = ImageUtil.bitmapToBase64(bitmap);
                    sendMsg(mLevel == 1 ? SignalRCode.TYPE_USER_IMG : SignalRCode.TYPE_GROUP_IMG, base64);
                    addImg(myId, myPhoto, bitmap, imgUrl, ChatCode.CHAT_MY_IMG);
                }
            }
        }
    };

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(EventBean event) {
        String msgType = event.getMsgType();
        if (msgType.equals(SignalRCode.TYPE_USER)) {
            return;
        }
        String msgJson = event.getMsg();
        if (msgType.equals(SignalRCode.TYPE_LOGIN)) {
            changeStatus(msgJson, "在线");
            return;
        }
        if (msgType.equals(SignalRCode.TYPE_LOGOUT)) {
            changeStatus(msgJson, "离线");
            return;
        }
        if (!event.isAdd()) {
            MsgDto<MsgContentDto> msgDto = (MsgDto<MsgContentDto>) GsonUtil.getInstance().fromJson(msgJson, new TypeToken<MsgDto<MsgContentDto>>() {
            }.getType());
            MsgContentDto msgDtoMsg = msgDto.getMsg();
            String content = msgDtoMsg.getContent();
            String fromId = msgDtoMsg.getFromId();
            switch (msgType) {
                case SignalRCode.TYPE_USER_WORD:
                case SignalRCode.TYPE_GROUP_WORD:
                    addWord(fromId, ImageUtil.getLocalPhoto(fromId), content, ChatCode.CHAT_OTHER_TEXT);
                    break;
                case SignalRCode.TYPE_USER_IMG:
                case SignalRCode.TYPE_GROUP_IMG:
                    Bitmap toBitmap = ImageUtil.base64ToBitmap(content);
                    String path = ImageUtil.saveBitmap(ChatListActivity.this, toBitmap);
                    addImg(fromId, ImageUtil.getLocalPhoto(fromId), toBitmap, path, ChatCode.CHAT_OTHER_IMG);
                    break;
                case SignalRCode.TYPE_USER_VOICE:
                case SignalRCode.TYPE_GROUP_VOICE:
                    String pathName = "demo_voice_" + DateUtil.DateTimeToStr(new Date(), "yyyyMMdd_hhmmss") + ".m4a";
                    String pathVoice = FileUtils.base64ToFile(ChatListActivity.this, content, pathName);
                    addVoice(fromId, ImageUtil.getLocalPhoto(fromId), pathVoice, ChatCode.CHAT_OTHER_VOICE);
                    break;
            }
        }
    }

    private void changeStatus(String json, String status) {
        MsgDto<UserDto> msgDto = (MsgDto<UserDto>) GsonUtil.getInstance().fromJson(json, new TypeToken<MsgDto<UserDto>>() {
        }.getType());
        UserDto userDto = msgDto.getMsg();
        if (userDto.getId().equals(otherId) && userDto.getLevel() == mLevel) {
            tvStatus.setText(status);
        }
    }

    private void sendMsg(String type, String msg) {
        MsgDto<MsgContentDto> bean = new MsgDto<>();
        bean.setMsgType(type);
        MsgContentDto dto = new MsgContentDto();
        dto.setFromId(myId);
        dto.setToId(otherId);
        dto.setContent(msg);
        bean.setMsg(dto);
        String json = GsonUtil.getInstance().toJson(bean);
        Log.i(AllConstants.TAG, json);
        SignalRUtil.getInstance().send(SignalRCode.SEND_MSG, type, json);
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_chat_list;
    }

    @Override
    protected void initView() {
        WindowUtil.setBarBgColor(this, R.color.color_ed);

        EventBus.getDefault().register(this);
        tvName = findViewById(R.id.tv_name);
        tvStatus = findViewById(R.id.tv_status);
        recyclerView.addOnScrollListener(new OnRecyclerViewScrollListener() {
            @Override
            public void onBottom() {
                super.onBottom();
                loadData();
            }
        });
        adapter = new ChatContentAdapter(this, this, list);
        adapter.setOnItemChildrenClickListener(new ChatContentAdapter.OnItemChildrenClickListener() {
            @Override
            public void OnItemChildrenClickListener(View v, int position) {
                switch (v.getId()) {
                    case R.id.iv_play:
                        mViewType = list.get(position).getViewType();
                        if (isPlay) {
                            audioPresenter.stopPlayRecord();
                            if (mLastPosition == position) {
                                return;
                            }
                        }
                        isPlay = true;
                        ivPlay = (ImageView) v;
                        mAnim = (AnimationDrawable) ivPlay.getBackground();
                        mAnim.start();
                        audioPresenter.startPlayRecord(list.get(position).getContent());
                        mLastPosition = position;
                        break;
                    case R.id.iv_content:
                        if (isPlay) {
                            audioPresenter.stopPlayRecord();
                        }
                        ArrayList<String> listImg = new ArrayList<>();
                        int pos = 0;
                        for (int i = 0; i < list.size(); i++) {
                            ChatBean bean = list.get(i);
                            if (bean.getViewType() == ChatCode.CHAT_MY_IMG
                                    || bean.getViewType() == ChatCode.CHAT_OTHER_IMG) {
                                listImg.add(bean.getContent());
                                if (i == position) {
                                    pos = listImg.size() - 1;
                                }
                            }
                        }
                        jumpPreview(listImg, pos);
                        break;
                    case R.id.iv_head:
                        if (isPlay) {
                            audioPresenter.stopPlayRecord();
                        }
                        ArrayList<String> listHead = new ArrayList<>();
                        listHead.add(list.get(position).getPhoto());
                        jumpPreview(listHead, 0);
                        break;
                }
            }
        });
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setStackFromEnd(true);
        layoutManager.setReverseLayout(true);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);
        recyclerView.setItemAnimator(null);
        ivLeft = findViewById(R.id.iv_left);
        ivAdd = findViewById(R.id.iv_add);
        etInput = findViewById(R.id.et_input);
        tvSend = findViewById(R.id.tv_send);
        etInput.addTextChangedListener(new MyTextWatcher());
        ivLeft.setOnClickListener(this);
        tvSend.setOnClickListener(this);
        ivAdd.setOnClickListener(this);
        findViewById(R.id.iv_back).setOnClickListener(this);
//        錄音
        tvAudio = findViewById(R.id.tv_audio);
        tvAudio.setOnVoiceIVCallBack(new MyOnVoiceIVCallBack());
        audioPresenter = new AudioPresenter<IAudioView.View>(this, this);
        audioPresenter.init();
    }

    @Override
    protected void initData() {
        myId = SPUtil.getInstance().getString(AllConstants.ID);
        myPhoto = ImageUtil.getLocalPhoto(myId);
        Intent intent = getIntent();
        otherId = intent.getStringExtra(AllConstants.OTHER_ID);
        ContactBean bean = SQLiteUtil.getInstance().queryContactById(otherId);
        tvName.setText(bean.getName());
        mLevel = bean.getLevel();
        SPUtil.getInstance().putString(AllConstants.OTHER_ID, otherId);
        loadData();
        recyclerView.scrollToPosition(0);
    }

    @Override
    protected void loadData() {
        offset = list.size();
        List<ChatBean> queryList = SQLiteUtil.getInstance().queryChatList(otherId, offset + "," + limit);
        if (!queryList.isEmpty()) {
            list.addAll(queryList);
            adapter.notifyDataSetChanged();
        }
    }

    private void jumpPreview(ArrayList<String> listImg, int pos) {
        Intent intent = new Intent();
        intent.setClass(ChatListActivity.this, ImagePreviewActivity.class);
        intent.putExtra(AllConstants.LIST_IMG, listImg);
        intent.putExtra(AllConstants.ID, pos);
        startActivity(intent);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_back:
                setResult(1);
                finish();
                break;
            case R.id.iv_left:
                changeType();
                break;
            case R.id.iv_add:
                if (WindowUtil.softInputStatus(etInput)) {
                    WindowUtil.hideSoftInput(etInput);
                }
                CommDialogUtils.showComboPicDialog(this);
                break;
            case R.id.tv_send:
                String text = etInput.getText().toString();
                sendMsg(mLevel == 1 ? SignalRCode.TYPE_USER_WORD : SignalRCode.TYPE_GROUP_WORD, text);
                addWord(myId, myPhoto, text, ChatCode.CHAT_MY_TEXT);
                etInput.setText(null);
                break;
        }
    }

    private void addVoice(String userId, String photo, String path, int type) {
        isOvertime();
        ChatBean bean = new ChatBean();
        bean.setChatId(otherId);
        bean.setUserId(userId);
        bean.setViewType(type);
        bean.setContent(path);
        bean.setPhoto(photo);
        bean.setDate(new Date());
        if (mLevel == 2) {
            bean.setGroupId(otherId);
        }
        adapter.add(bean);
        recyclerView.scrollToPosition(0);
        SQLiteUtil.getInstance().insertChat(bean);
    }

    private void addImg(String userId, String photo, Bitmap bitmap, String path, int type) {
        isOvertime();
        ChatBean bean = new ChatBean();
        bean.setChatId(otherId);
        bean.setUserId(userId);
        bean.setContent(path);
        if (bitmap.getWidth() > DensityUtil.dp2px(120)) {
            bean.setPhotoW(DensityUtil.dp2px(120));
            bean.setPhotoH((int) (DensityUtil.dp2px(120) * ((float) bitmap.getHeight() / bitmap.getWidth())));
        } else if (bitmap.getWidth() < DensityUtil.dp2px(10)) {
            bean.setPhotoW(DensityUtil.dp2px(10));
            bean.setPhotoH((int) (DensityUtil.dp2px(10) * ((float) bitmap.getWidth() / bitmap.getHeight())));
        } else {
            bean.setPhotoW(bitmap.getWidth());
            bean.setPhotoH(bitmap.getHeight());
        }
        bean.setViewType(type);
        bean.setPhoto(photo);
        bean.setDate(new Date());
        if (mLevel == 2) {
            bean.setGroupId(otherId);
        }
        adapter.add(bean);
        recyclerView.scrollToPosition(0);
        SQLiteUtil.getInstance().insertChat(bean);
    }

    private void addWord(String userId, String photo, String msg, int type) {
        isOvertime();
        ChatBean bean = new ChatBean();
        bean.setChatId(otherId);
        bean.setUserId(userId);
        bean.setPhoto(photo);
        bean.setViewType(type);
        bean.setContent(msg);
        bean.setDate(new Date());
        if (mLevel == 2) {
            bean.setGroupId(otherId);
        }
        adapter.add(bean);
        recyclerView.scrollToPosition(0);
        SQLiteUtil.getInstance().insertChat(bean);
    }

    /**
     * 新消息时间距离上一条消息时间是否已超5分钟
     * 是则添加一条时间item
     */
    private void isOvertime() {
        if (!list.isEmpty()) {
            if (DateUtil.isOvertime(list.get(0).getDate())) {
                ChatBean bean = new ChatBean();
                bean.setChatId(otherId);
                bean.setViewType(ChatCode.CHAT_TIME);
                bean.setDate(new Date());
                adapter.add(bean);
                SQLiteUtil.getInstance().insertChat(bean);
            }
        }
    }

    /**
     * 切换输入/语音
     */
    private void changeType() {
        ivLeft.setSelected(!ivLeft.isSelected());
        if (ivLeft.isSelected()) {
            tvAudio.setVisibility(View.VISIBLE);
            etInput.setVisibility(View.GONE);
            // 隱藏鍵盤
            if (WindowUtil.softInputStatus(etInput)) {
                WindowUtil.hideSoftInput(etInput);
            }
            // 隱藏“發送”按鈕
            if (tvSend.getVisibility() == View.VISIBLE) {
                tvSend.setVisibility(View.GONE);
                ivAdd.setVisibility(View.VISIBLE);
            }
        } else {
            tvAudio.setVisibility(View.GONE);
            etInput.setVisibility(View.VISIBLE);
            etInput.requestFocus();
            WindowUtil.showSoftInput(etInput);
            recyclerView.scrollToPosition(0);
            // 輸入框不為空，顯示“發送”按鈕
            if (!etInput.getText().toString().isEmpty()) {
                tvSend.setVisibility(View.VISIBLE);
                ivAdd.setVisibility(View.GONE);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (PermissionUtil.requestPermission(grantResults)) {
            if (requestCode == AllConstants.PIC_CAMERA) {
                PhotoUtil.getInstance().toCamera(this);
            } else if (requestCode == AllConstants.PIC_GALLERY) {
                PhotoUtil.getInstance().toGallery(this);
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != 0) {
            if (requestCode == AllConstants.PIC_CAMERA) {
                showLocalPic(PhotoUtil.getInstance().imgUrl);
            } else if (requestCode == AllConstants.PIC_GALLERY) {
                showLocalPic(FileUtils.getFilePathByUri(this, data.getData()));
            }
        }
    }

    String imgUrl;

    private void showLocalPic(String imgUrl) {
        this.imgUrl = imgUrl;
        ImageUtil.getBitmap(this, imgUrl, handler, ImageEditCode.BITMAP_ARG);
    }

    @Override
    public void showNormalTipView() {
        if (popIsNull()) {
            mRecordVoicePopWindow = new RecordVoicePopWindow(this);
        }
        mRecordVoicePopWindow.showAtLocation(getWindow().getDecorView(), Gravity.CENTER, 0, 0);
    }

    @Override
    public void showTimeOutTipView(int remainder) {
        if (!popIsNull()) {
            mRecordVoicePopWindow.showTimeOutTipView(remainder);
        }
    }

    @Override
    public void showRecordingTipView() {
        if (!popIsNull()) {
            mRecordVoicePopWindow.showRecordingTipView();
        }
    }

    @Override
    public void showRecordTooShortTipView() {
        if (!popIsNull()) {
            mRecordVoicePopWindow.showRecordTooShortTipView();
        }
    }

    @Override
    public void showCancelTipView() {
        if (!popIsNull()) {
            mRecordVoicePopWindow.showCancelTipView();
        }
    }

    @Override
    public void hideTipView() {
        if (!popIsNull()) {
            mRecordVoicePopWindow.dismiss();
        }
    }

    @Override
    public void updateCurrentVolume(int db) {
        if (!popIsNull()) {
            mRecordVoicePopWindow.updateCurrentVolume(db);
        }
    }

    @Override
    public void finishRecord(String file) {
        addVoice(myId, myPhoto, file, ChatCode.CHAT_MY_VOICE);
        String base64 = FileUtils.fileToBase64(file);
        sendMsg(mLevel == 1 ? SignalRCode.TYPE_USER_VOICE : SignalRCode.TYPE_GROUP_VOICE, base64);
    }

    @Override
    public void finishPlayAudio() {
        if (ivPlay != null) {
            ivPlay.setBackgroundResource(mViewType == ChatCode.CHAT_MY_VOICE ? R.drawable.ic_my_voice_play : R.drawable.ic_other_voice_play);
        }
        if (mAnim != null) {
            mAnim.stop();
            mAnim = null;
        }
        isPlay = false;
    }

    private boolean popIsNull() {
        return mRecordVoicePopWindow == null;
    }

    class MyTextWatcher implements TextWatcher {

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            int visibility = tvSend.getVisibility();
            if (TextUtils.isEmpty(s.toString())) {
                if (visibility == View.VISIBLE) {
                    tvSend.setVisibility(View.GONE);
                    ivAdd.setVisibility(View.VISIBLE);
                }
            } else {
                if (visibility == View.GONE) {
                    tvSend.setVisibility(View.VISIBLE);
                    ivAdd.setVisibility(View.GONE);
                }
            }
        }
    }

    class MyOnVoiceIVCallBack implements RecordAudioTextView.OnVoiceIVCallBack {

        @Override
        public void onStartRecord() {
            if (PermissionUtil.addPermission(ChatListActivity.this,
                    new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    AllConstants.RECORD_AUDIO)) {
                audioPresenter.startRecord();
            }
        }

        @Override
        public void onStopRecord() {
            audioPresenter.stopRecord();
        }

        @Override
        public void onWillCancelRecord() {
            audioPresenter.willCancelRecord();
        }

        @Override
        public void onContinueRecord() {
            audioPresenter.continueRecord();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (list.isEmpty()) {
            return;
        }
        ChatBean chatBean = list.get(0);
        ContactBean bean = new ContactBean();
        bean.setUserOrGroupId(otherId);
        bean.setLevel(mLevel);
        bean.setDate(chatBean.getDate());
        bean.setNum(0);
        String content = "";
        int viewType = chatBean.getViewType();
        if (viewType == ChatCode.CHAT_MY_TEXT || viewType == ChatCode.CHAT_OTHER_TEXT) {
            content = chatBean.getContent();
        } else if (viewType == ChatCode.CHAT_MY_IMG || viewType == ChatCode.CHAT_OTHER_IMG) {
            content = "[图片]";
        } else if (viewType == ChatCode.CHAT_MY_VOICE || viewType == ChatCode.CHAT_OTHER_VOICE) {
            content = "[语音]";
        }
        if (mLevel == 2) {
            ContactBean contactById = SQLiteUtil.getInstance().queryContactById(chatBean.getUserId());
            content = contactById.getName() + "：" + content;
        }
        bean.setContent(content);
        SQLiteUtil.getInstance().updateContact(bean);

    }

    @Override
    public void onBackPressed() {
        setResult(1);
        finish();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}